package compoundDB.core;

import static org.junit.Assert.*;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import org.junit.Test;

import compoundDB.database.DBManager;
import compoundDB.database.DatabaseTests;
import compoundDB.database.QueryReader;
import compoundDB.database.enumeration.DataType;

public class GUIControllerImplTest
{
	@Test
	public void testAddCompound() throws ClassNotFoundException, SQLException
	{
		DatabaseTests.setupTestDatabase();
		DBManager dbm = new DBManager();
		GUIControllerImpl gci = new GUIControllerImpl(dbm);
		dbm.openDatabaseConnection();
		
		Object[] props = new Object[8];
		String[] names = new String[3];
		names[0] = "name11";
		names[1] = "name12";
		names[2] = "name13";
		props[2] = 1L;
		props[3] = "tags test1";
		props[4] = "Test Smiles 1";
		props[5] = "String that shouldnt be added but shouldnt cause crash";
		props[6] = "test link 1";
		props[7] = "test note 1";
		
		gci.addCompound(props, names);
		
		// Check database directly
		Connection conn = DatabaseTests.getNewConnection();
		Statement st = conn.createStatement();
		ResultSet rs = st.executeQuery("SELECT * FROM compounds");
		
		rs.next();
		
		rs.next();
		assertTrue(rs.getInt(1) == 2);
		assertTrue(rs.getInt(2) == 0);
		assertTrue(rs.getString(3).equals("tags test1"));
		assertTrue(rs.getString(4).equals("Test Smiles 1"));
		assertTrue(rs.getBytes(5) == null);
		assertTrue(rs.getString(6).equals("test link 1"));
		assertTrue(rs.getString(7).equals("test note 1"));
		
		rs.close();
		rs = st.executeQuery("SELECT * FROM compound_names");
		
		rs.next();
		
		rs.next();
		assertTrue(rs.getString(2).equals("name11"));
		rs.next();
		assertTrue(rs.getString(2).equals("name12"));
		rs.next();
		assertTrue(rs.getString(2).equals("name13"));
		
		rs.close();
		st.close();
		conn.close();
	}
	
	@Test
	public void testGetEditCompound() throws ClassNotFoundException,
			SQLException
	{
		DatabaseTests.setupTestDatabase();
		DatabaseTests.populateDatabase();
		DBManager dbm = new DBManager();
		GUIControllerImpl gci = new GUIControllerImpl(dbm);
		dbm.openDatabaseConnection();
		
		// Get compound
		Object[] comparray = gci.getCompound(2L);
		
		// Check changes were made correctly
		assertTrue(comparray.length == 8);
		assertTrue(comparray[0].equals(Boolean.valueOf(false)));
		assertTrue(comparray[1].equals(2L));
		assertTrue(comparray[2].equals(2L));
		assertTrue(comparray[3].equals("tags2"));
		assertTrue(comparray[4].equals("smiles2"));
		assertTrue(comparray[5] == null);
		assertTrue(comparray[6].equals("links2"));
		assertTrue(comparray[7].equals("notes2"));
		
		// Edit compound
		comparray[3] = "edited tag";
		String[] names = new String[2];
		names[0] = "edited name";
		names[1] = "edited name again";
		comparray[5] = new byte[15];
		comparray[6] = "www.xkcd.com/505/";
		
		// Submit changes
		gci.editCompound(comparray, names);
		
		// Get updated compound
		List<Long> guids = new ArrayList<Long>();
		guids.add(2L);
		QueryReader rdr = dbm.getCompounds(guids);
		Compound comp = rdr.getCompounds(1, 1).get(0);
		
		// Check changes were made correctly
		assertTrue(comp.getNames().size() == 2);
		assertTrue(comp.getNames().get(0).equals("edited name"));
		assertTrue(comp.getNames().get(1).equals("edited name again"));
		assertTrue(comp.getProperty("tags").equals("edited tag"));
		assertTrue(comp.getProperty("links").equals("www.xkcd.com/505/"));
		
		// Get edited compound via guicontroller
		comparray = gci.getCompound(2L);
		
		// Check changes are correct via guicontroller get compound
		assertTrue(comparray.length == 8);
		assertTrue(comparray[0].equals(Boolean.valueOf(false)));
		assertTrue(comparray[1].equals(2L));
		assertTrue(comparray[2].equals(2L));
		assertTrue(comparray[3].equals("edited tag"));
		assertTrue(comparray[4].equals("smiles2"));
		assertTrue(comparray[5] == null);
		assertTrue(comparray[6].equals("www.xkcd.com/505/"));
		assertTrue(comparray[7].equals("notes2"));
	}
	
	@Test
	public void testDeleteCompound() throws ClassNotFoundException,
			SQLException
	{
		DatabaseTests.setupTestDatabase();
		DatabaseTests.populateDatabase();
		DBManager dbm = new DBManager();
		GUIControllerImpl gci = new GUIControllerImpl(dbm);
		dbm.openDatabaseConnection();
		
		List<Long> guids = new ArrayList<Long>();
		guids.add(4L);
		guids.add(1L);
		guids.add(3L);
		guids.add(2L);
		guids.add(5L);
		
		List<Long> deleteGuids = new ArrayList<Long>();
		deleteGuids.add(3L);
		deleteGuids.add(5L);
		gci.deleteCompound(deleteGuids);
		
		QueryReader rdr = dbm.getCompounds(guids);
		
		assertTrue(rdr.getCompoundCount() == 3);
		
		List<Compound> comps = rdr.getCompounds(1, 3);
		
		assertTrue(comps.get(0).getGUID() == 1);
		assertTrue(comps.get(0).getNames().size() == 1);
		assertTrue(comps.get(0).getNames().get(0).equals("Test Compound"));
		assertTrue(comps.get(0).getOwnerID() == 0);
		assertTrue(comps.get(0).getProperties().size() == 7);
		assertTrue(comps.get(0).getProperty("tags").equals("test"));
		
		assertTrue(comps.get(1).getGUID() == 2);
		assertTrue(comps.get(1).getNames().size() == 2);
		assertTrue(comps.get(1).getNames().get(0).equals("comp21"));
		assertTrue(comps.get(1).getNames().get(1).equals("comp22"));
		assertTrue(comps.get(1).getOwnerID() == 2);
		assertTrue(comps.get(1).getProperties().size() == 7);
		assertTrue(comps.get(1).getProperty("tags").equals("tags2"));
		
		assertTrue(comps.get(2).getGUID() == 4);
		assertTrue(comps.get(2).getNames().size() == 3);
		assertTrue(comps.get(2).getNames().get(0).equals("comp41"));
		assertTrue(comps.get(2).getNames().get(1).equals("comp42"));
		assertTrue(comps.get(2).getNames().get(2).equals("comp43"));
		assertTrue(comps.get(2).getOwnerID() == 4);
		assertTrue(comps.get(2).getProperties().size() == 7);
		assertTrue(comps.get(2).getProperty("tags").equals("tags4"));
	}
	
	@Test
	public void testQuickSearch_GetSearchResults_GetSearchResultCount()
			throws ClassNotFoundException, SQLException
	{
		DatabaseTests.setupTestDatabase();
		DatabaseTests.populateDatabase();
		DBManager dbm = new DBManager();
		GUIControllerImpl gci = new GUIControllerImpl(dbm);
		dbm.openDatabaseConnection();
		
		// Check getting a single result
		gci.quickSearch("comp");
		
		Object[][] comps = gci.getSearchResults(1, 1);
		assertTrue(comps.length == 1);
		
		assertTrue(comps[0][0].equals(Boolean.valueOf(false)));
		assertTrue(comps[0][1].equals(2L));
		assertTrue(comps[0][2].equals(2L));
		assertTrue(comps[0][3].equals("tags2"));
		assertTrue(comps[0][4].equals("smiles2"));
		assertTrue(comps[0][6].equals("links2"));
		assertTrue(comps[0][7].equals("notes2"));
		
		// Check getting more than one result, and a result offset
		gci.quickSearch("comp");
		
		comps = gci.getSearchResults(2, 2);
		assertTrue(comps.length == 2);
		
		assertTrue(comps[0][0].equals(Boolean.valueOf(false)));
		assertTrue(comps[0][1].equals(3L));
		assertTrue(comps[0][2].equals(3L));
		assertTrue(comps[0][3].equals("tags3"));
		assertTrue(comps[0][4].equals("smiles3"));
		assertTrue(comps[0][6].equals("links3"));
		assertTrue(comps[0][7].equals("notes3"));
		
		assertTrue(comps[1][0].equals(Boolean.valueOf(false)));
		assertTrue(comps[1][1].equals(4L));
		assertTrue(comps[1][2].equals(4L));
		assertTrue(comps[1][3].equals("tags4"));
		assertTrue(comps[1][4].equals("smiles4"));
		assertTrue(comps[1][6].equals("links4"));
		assertTrue(comps[1][7].equals("notes4"));
		
		// Check different search
		gci.quickSearch("Test");
		
		comps = gci.getSearchResults(1, 4);
		assertTrue(comps.length == 1);
		
		assertTrue(comps[0][0].equals(Boolean.valueOf(false)));
		assertTrue(comps[0][1].equals(1L));
		assertTrue(comps[0][2].equals(0L));
		assertTrue(comps[0][3].equals("test"));
		assertTrue(comps[0][4].equals("C-Test"));
		assertTrue(comps[0][6].equals("www.test.net"));
		assertTrue(comps[0][7].equals("test notes here"));
	}
	
	@Test
	public void testGetCompoundNames() throws ClassNotFoundException,
			SQLException
	{
		DatabaseTests.setupTestDatabase();
		DatabaseTests.populateDatabase();
		DBManager dbm = new DBManager();
		GUIControllerImpl gci = new GUIControllerImpl(dbm);
		dbm.openDatabaseConnection();
		
		String[] names = gci.getCompoundNames(2L);
		
		assertTrue(names.length == 2);
		assertTrue(names[0].equals("comp21"));
		assertTrue(names[1].equals("comp22"));
		
		names = gci.getCompoundNames(4L);
		
		assertTrue(names.length == 3);
		assertTrue(names[0].equals("comp41"));
		assertTrue(names[1].equals("comp42"));
		assertTrue(names[2].equals("comp43"));
	}
	
	@Test
	public void testGet_Add_Delete_Rename_Column()
			throws ClassNotFoundException, SQLException
	{
		DatabaseTests.setupTestDatabase();
		DBManager dbm = new DBManager();
		GUIControllerImpl gci = new GUIControllerImpl(dbm);
		dbm.openDatabaseConnection();
		
		// Test default columns are okay
		String[] cols = gci.getColumnTitles();
		
		assertTrue(cols.length == 8);
		
		// Check pre-existing are okay
		assertTrue(cols[1].equals("guid"));
		assertTrue(cols[2].equals("ownerid"));
		assertTrue(cols[3].equals("tags"));
		assertTrue(cols[4].equals("smiles"));
		assertTrue(cols[6].equals("links"));
		assertTrue(cols[7].equals("notes"));
		
		
		// Test Add some new columns
		gci.addColumn("newProp1", DataType.LONG);
		gci.addColumn("newProp2", DataType.BYTES);
		gci.addColumn("newProp3", DataType.DOUBLE);
		gci.addColumn("newProp4", DataType.FLOAT);
		gci.addColumn("newProp5", DataType.INTEGER);
		
		// Test Get columns were added successfully
		cols = gci.getColumnTitles();
		
		assertTrue(cols.length == 13);
		
		// Check pre-existing still exist
		assertTrue(cols[1].equals("guid"));
		assertTrue(cols[2].equals("ownerid"));
		assertTrue(cols[3].equals("tags"));
		assertTrue(cols[4].equals("smiles"));
		assertTrue(cols[6].equals("links"));
		assertTrue(cols[7].equals("notes"));
		
		// Check new names
		assertTrue(cols[8].equals("newProp1"));
		assertTrue(cols[9].equals("newProp2"));
		assertTrue(cols[10].equals("newProp3"));
		assertTrue(cols[11].equals("newProp4"));
		assertTrue(cols[12].equals("newProp5"));
		
		// Test Remove
		gci.deleteColumn(cols[9]);
		cols = gci.getColumnTitles();
		
		assertTrue(cols.length == 12);
		// Check names are right
		assertTrue(cols[8].equals("newProp1"));
		assertTrue(cols[9].equals("newProp3"));
		assertTrue(cols[10].equals("newProp4"));
		assertTrue(cols[11].equals("newProp5"));
		
		// Test Rename
		gci.renameColumn(cols[9], "renamedProp1");
		cols = gci.getColumnTitles();
		
		assertTrue(cols.length == 12);
		// Check names are right
		assertTrue(cols[8].equals("newProp1"));
		assertTrue(cols[9].equals("renamedProp1"));
		assertTrue(cols[10].equals("newProp4"));
		assertTrue(cols[11].equals("newProp5"));
		
		dbm.closeDatabaseConnection();
	}
}
